Terraform で Auto Mode の EKS クラスターを作成して、Pod Identity で AWS 権限を与えたアプリケーションをデプロイしてみた
今回は Auto Mode の EKS クラスターを Terraform で作ってみようと思います。
また、Auto Mode には Pod Identity エージェントの設定不要で Pod Identity を利用できるメリットがあるので、合わせて試してみます。
Auto Mode とは?
ノードやアドオンの管理を AWS 側にオフロードできる EKS の新しい機能です。
Pod Identity とは?
昨年末のアップデートで利用できるようになった、ServiceAccount 単位で Pod へ AWS 権限を付与できる機能です。
旧来から存在する IRSA(IAM Roles for Service Accounts)でも Service Account 単位での権限管理を行うことは可能ですが、IAM ロールの信頼ポリシーとマニフェストファイルでの annotations 設定を両方行う必要があります。
信頼ポリシーに下記のような Open ID Connect プロバイダーから AssumeRole する許可設定を行う必要があります。
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Principal": {
"Federated": "arn:aws:iam::111122223333:oidc-provider/oidc.eks.region-code.amazonaws.com/id/EXAMPLED539D4633E53DE1B71EXAMPLE"
},
"Action": "sts:AssumeRoleWithWebIdentity"
}
]
}
また、Kubernetes のマニフェストファイル側でも annotations 設定を行う必要があります。
apiVersion: v1
kind: ServiceAccount
metadata:
annotations:
eks.amazonaws.com/role-arn: arn:aws:iam::444455556666:role/account-b-role
Pod Identity を利用することで、AWS 側の設定だけでより簡潔に設定を行うことができます。
ただ、Pod Identity Agent という専用エージェントをインストールする必要があり、利用する前に一手間必要でした。
Auto Mode の場合はこの辺りもプリインストールされているので、より簡単に利用することができます。
やってみる
Terraform で EKS を作成して、FastAPI のアプリケーションをデプロイします。
アプリケーションから DynamoDB にアクセスして、AWS の権限を扱えることを確認します。
本ブログでは特徴的な部分についてのみ説明しますが、利用したファイルは下記リポジトリにアップロードしました。
もし興味があればご参照下さい。
EKS は関連リソースが多くて定義が煩雑になりがちなので、下記公開モジュールを利用します。
Terraform の EKS 構築部分は下記のようになります。
module "eks" {
source = "terraform-aws-modules/eks/aws"
version = "~> 20.31.6"
cluster_name = "test-cluster"
cluster_version = "1.31"
cluster_endpoint_public_access = true
vpc_id = module.vpc.vpc_id
subnet_ids = module.vpc.private_subnets
enable_cluster_creator_admin_permissions = true
cluster_compute_config = {
enabled = true
node_pools = ["general-purpose"]
}
}
data "aws_iam_policy_document" "allow_pod_identity" {
statement {
effect = "Allow"
principals {
type = "Service"
identifiers = ["pods.eks.amazonaws.com"]
}
actions = [
"sts:AssumeRole",
"sts:TagSession"
]
}
}
resource "aws_iam_role" "read_dynamodb" {
name = "read-dynamodb-role"
assume_role_policy = data.aws_iam_policy_document.allow_pod_identity.json
}
resource "aws_iam_role_policy_attachment" "read_dynamodb" {
role = aws_iam_role.read_dynamodb.name
policy_arn = "arn:aws:iam::aws:policy/AmazonDynamoDBReadOnlyAccess"
}
resource "aws_eks_pod_identity_association" "read_dynamodb" {
cluster_name = module.eks.cluster_name
namespace = "app"
service_account = "app-sa"
role_arn = aws_iam_role.read_dynamodb.arn
}
cluster_compute_config
で enabled=true
に設定することで Auto Mode を有効化できます。
module.eks
が EKS クラスター自体の定義で、それ以降は Pod Identity の定義になります。
ここでは Service Account(app-sa) を指定した Pod に DynamoDB の読み取り権限を付与しています。
また、アドオンは一つも追加していません。
今回利用する AWS Load Balancer Controller と Pod Identity エージェントは最初からインストールされているので、特に設定不要で利用できます。
ノードの管理についても Auto Mode の裏で動作している Karpenter に任せるため、設定不要です。
IRSA は利用しないため、OIDC ID プロバイダー関連の設定も不要になります。
アプリケーションとしては DynamoDB の項目を読み取って表示するだけの簡単な物を利用します。
from fastapi import FastAPI
import boto3
app = FastAPI()
@app.get("/")
def read_root():
dynamodb = boto3.client("dynamodb", region_name="ap-northeast-1")
response = dynamodb.scan(
TableName="test-dynamodb",
)
return response["Items"]
Terraform で作成した EKS クラスターに対して、Kubernetes リソースを作成していきます。
Namespace を作成します。
apiVersion: v1
kind: Namespace
metadata:
name: app
Service Account を作成します。
apiVersion: v1
kind: ServiceAccount
metadata:
name: app-sa
namespace: app
作成した Service Account を指定して、アプリケーションをデプロイします。
Pod Identity で app-sa に対して権限を付与しているので、これらの Pod から DynamoDB にアクセスできます。
apiVersion: apps/v1
kind: Deployment
metadata:
namespace: app
name: fastapi-app
spec:
selector:
matchLabels:
app.kubernetes.io/name: fastapi-app
replicas: 2
template:
metadata:
labels:
app.kubernetes.io/name: fastapi-app
spec:
serviceAccountName: app-sa
containers:
- image: <AccountID>.dkr.ecr.ap-northeast-1.amazonaws.com/fastapi-app:latest
imagePullPolicy: Always
name: fastapi-app
ports:
- containerPort: 8080
resources:
requests:
cpu: "0.5"
Pod を作成したタイミングで、Karpenter が自動でノードを作成してくれました。
AWS に任せられる範囲が増えて良い感じです。
インターネット経由でアプリケーションにアクセスしたいので、Ingress 関連のリソースをデプロイしていきます。
まず Service をデプロイします。
apiVersion: v1
kind: Service
metadata:
namespace: app
name: app-service
spec:
ports:
- port: 8080
targetPort: 8080
protocol: TCP
type: NodePort
selector:
app.kubernetes.io/name: fastapi-app
IngressClass をデプロイします。
apiVersion: networking.k8s.io/v1
kind: IngressClass
metadata:
namespace: app
labels:
app.kubernetes.io/name: LoadBalancerController
name: alb
spec:
controller: eks.amazonaws.com/alb
Ingress をデプロイします。
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
namespace: app
name: app-ingress
annotations:
alb.ingress.kubernetes.io/scheme: internet-facing
alb.ingress.kubernetes.io/target-type: ip
spec:
ingressClassName: alb
rules:
- http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: app-service
port:
number: 8080
DynamoDB にサンプルデータを格納します。
ALB が作成されていることを確認します。
% kubectl get ingress -n app
NAME CLASS HOSTS ADDRESS PORTS AGE
app-ingress alb * k8s-app-appingre-87880d3dc3-2089073335.ap-northeast-1.elb.amazonaws.com 80 9s
ALB の DNS 名に対してリクエストを送ると DynamoDB のデータを取得できています。
% curl http://k8s-app-appingre-87880d3dc3-2089073335.ap-northeast-1.elb.amazonaws.com/
[{"UserId":{"S":"2"},"Point":{"N":"70"}},{"UserId":{"S":"1"},"Point":{"N":"80"}}]
Pod Identity エージェント、AWS Load Balancer Controller、Karpenter と全て設定不要で利用することができました!
まとめ
Auto Mode のクラスターを構築して、AWS 権限を必要とするアプリケーションの公開まで実施してみました。
Auto Mode では管理する対象が減るので Terraform の記載もシンプルになって良いですね。
直近 EKS をよりシンプルに使うためのアップデートが継続的に公開されており、1 年半前くらいと比べて設定に躓きそうな部分も格段に減った気がします。
皆さんも是非試してみて下さい!